#include "dvc.h"
#include "stdio.h"
#include "string.h"
#include "dvc_log.h"

#define DVC_DEBUG 1

#if DVC_DEBUG
#include "stdio.h"
#define log_write printf
#else
#define log_write(x)
#endif

#ifdef DVC_ENABLE_LOG
uint16_t dvc_log_print_to(dvc_t dvc, dvc_log_t *log, void *buf, uint16_t len)
{
    if (!dvc || !log || !buf || len < 64)
        return 0;
    char *p = (char *)buf;
    p += sprintf(p, "{");                                                   /* 1 */
    p += sprintf(p, "\"voltage\":%.3f,", log->voltage);                     /* 11 */
    p += sprintf(p, "\"current\":%.3f,", log->current);                     /* 11 */
    p += sprintf(p, "\"power\":%.3f,", log->power);                         /* 9 */
    p += sprintf(p, "\"temp\":%u.%02u,", log->temp / 100, log->temp % 100); /* 8 */
    p += sprintf(p, "\"time\":%lu,", log->timestamp);                       /* 8 */
    p += sprintf(p, "\"bat\":[");                                           /* 8 */
    if (((intptr_t)p - (intptr_t)buf) > len)
        return 0;
    for (uint8_t i = 0; i < dvc->bat_num; i++)
    {
        p += sprintf(p, "%d.%03d,", log->bat_voltage[i] / 1000, log->bat_voltage[i] % 1000);
        if (((intptr_t)p - (intptr_t)buf) > len)
            return 0;
    }
    p--;
    p += sprintf(p, "]"); /* 1 */
    p += sprintf(p, "}"); /* 1 */
    if (((intptr_t)p - (intptr_t)buf) > len)
        return 0;
    return ((intptr_t)p - (intptr_t)buf);
}

void dvc_log_print(dvc_t dvc, dvc_log_t *log)
{
    log_write("[dvc] [%lu] vol:%.3f cur:%.3f power:%.3f temp:%d.%02d bat[",
              log->timestamp, log->voltage, log->current, log->power, log->temp / 100, log->temp % 100);
    for (uint8_t i = 0; i < dvc->bat_num; i++)
        log_write("%d.%03d,", log->bat_voltage[i] / 1000, log->bat_voltage[i] % 1000);
    log_write("]\n");
}
void dvc_log_clear(dvc_t dvc)
{
    if (!dvc)
        return;
    memset(dvc->log.sec, 0, sizeof(dvc->log.sec));
    memset(dvc->log.min, 0, sizeof(dvc->log.min));
    memset(dvc->log.hour, 0, sizeof(dvc->log.hour));
    memset(dvc->log.day, 0, sizeof(dvc->log.day));
    memset(dvc->log.years, 0, sizeof(dvc->log.years));
    dvc->log.years_w = 0;
}
void dvc_log_record_sec(dvc_t dvc, dvc_log_t *log)
{
    if (!dvc || !log)
        return;
    log->voltage = dvc->voltage;
    log->current = dvc->coulomb_counter.sec.mA / 1000.0f /* mA->A */;
    log->power = dvc->coulomb_counter.sec.mW / 1000.0; /* mW->W */
    for (uint8_t i = 0; i < dvc->bat_num; i++)
        log->bat_voltage[i] = dvc->bat_vol[i];
    log->temp = dvc->temp * 100;
    log->timestamp = dvc->tick;
    if (dvc->ops)
    {
        if (dvc->ops->get_time)
            log->timestamp = dvc->ops->get_time();
        if (dvc->ops->log_push)
            dvc->ops->log_push(dvc, DVC_LOG_PUSH_TYPE_SEC, log, NULL);
    }
}

void dvc_log_record(dvc_t dvc, uint8_t type, dvc_log_t *log, uint8_t time_type)
{
    if (!dvc || !log)
        return;
    float voltage = 0.0, current = 0.0, power = 0.0;
    float bat[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
    uint32_t temp = 0;
    uint16_t count = 60;
    if (time_type == DVC_LOG_PUSH_TYPE_YEARS) /* day */
        count = (dvc->sec_tick / 60) % 1440 + 1;
    uint16_t sum_len = 0;
    for (uint8_t i = 0; i < count; i++)
    {
        dvc_log_t *target_log = &dvc->log.sec[i];
        if (time_type == DVC_LOG_PUSH_TYPE_HOUR) /* hour */
            target_log = &dvc->log.min[i];
        else if (time_type == DVC_LOG_PUSH_TYPE_YEARS) /* day */
            target_log = &dvc->log.day[i];
        if (!(target_log->voltage > 0.001f))
            continue;
        sum_len++;
        voltage += target_log->voltage;
        current += target_log->current;
        power += target_log->power;
        temp += target_log->temp;
        for (uint8_t j = 0; j < dvc->bat_num; j++)
            bat[j] += target_log->bat_voltage[j];
    }
    if (!sum_len)
        sum_len++;
    log->voltage = voltage / sum_len;
    log->current = current / sum_len;
    log->power = power / sum_len;
    for (uint8_t i = 0; i < dvc->bat_num; i++)
        log->bat_voltage[i] = bat[i] / sum_len;
    log->temp = temp / sum_len;
    // 如果dvc有ops且ops中有get_time函数，则使用get_time函数获取时间戳
    if (dvc->ops && dvc->ops->get_time)
        log->timestamp = dvc->ops->get_time();
    else
        log->timestamp = dvc->tick;
    if (dvc->ops && dvc->ops->log_push)
        dvc->ops->log_push(dvc, type, log, NULL);
}

void dvc_log_record_minc(dvc_t dvc, dvc_log_t *log)
{
    dvc_log_record(dvc, DVC_LOG_PUSH_TYPE_MIN, log, 0);
    memcpy(&dvc->log.day[(dvc->sec_tick / 60) % 1440], log, sizeof(dvc_log_t));
}

void dvc_log_record_hour(dvc_t dvc, dvc_log_t *log)
{
    dvc_log_record(dvc, DVC_LOG_PUSH_TYPE_HOUR, log, 1);
}
void dvc_log_record_years(dvc_t dvc, dvc_log_t *log)
{
    if (!dvc || !log)
        return;
    dvc->log.years[dvc->log.years_w++] = *log;
    dvc->log.years_w %= 366;
}
#endif

#ifdef DVC_ENABLE_EVENT_LOG
void dvc_log_event_clear(dvc_t dvc)
{
    if (!dvc)
        return;
    memset(dvc->log.event, 0, sizeof(dvc->log.event));
    dvc->log.event_w = 0;
}
void dvc_log_event_push_only(dvc_t dvc, dvc_log_event_t *log)
{
    // 如果dvc或log为空，则返回
    if (!dvc || !log)
        return;

    // 将log事件推送到dvc的log.event数组中
    dvc->log.event[dvc->log.event_w++] = *log;
    // 对dvc的log.event_w进行取模运算，使其在数组范围内循环
    dvc->log.event_w %= (sizeof(dvc->log.event) / sizeof(dvc->log.event[0]));
}

// 函数dvc_log_event_push用于将日志事件推送到dvc中
void dvc_log_event_push(dvc_t dvc, dvc_log_event_t *log)
{
    // 如果dvc或log为空，则返回
    if (!dvc || !log)
        return;
    // 如果dvc有ops且ops中有get_time函数，则使用get_time函数获取时间戳
    if (dvc->ops && dvc->ops->get_time)
        log->timestamp = dvc->ops->get_time();

    dvc_log_event_push_only(dvc, log);

    /* 过滤初始化后的前3秒事件 */
    if (dvc->tick >= 3000 && dvc->ops)
    {
        if (dvc->ops->save_log)
            dvc->ops->save_log((uint8_t *)log, 1);
        if (dvc->ops->log_push)
            dvc->ops->log_push(dvc, 0, NULL, log);
    }
}
// 函数dvc_log_event_record用于记录事件
void dvc_log_event_record(dvc_t dvc, uint8_t flag, uint8_t event, uint8_t state)
{
    // 如果dvc或event为空，则返回
    if (!dvc || event == DVC_EVENT_TYPE_NONE)
        return;
    // 创建事件日志
    dvc_log_event_t event_log = {.timestamp = dvc->tick, .event = event, .flag = DVC_EVENT_FLAG_AFE, .state = state};
    // 将事件日志推入日志队列
    dvc_log_event_push(dvc, &event_log);
}
uint16_t dvc_log_event_print_to(dvc_t dvc, dvc_log_event_t *log, void *buf, uint16_t len)
{
    if (!dvc || !log || !buf || len < 48)
        return 0;
    char *p = (char *)buf;
    p += sprintf(p, "{");                             /* 1 */
    p += sprintf(p, "\"time\":%lu,", log->timestamp); /* 8 + 10 */
    p += sprintf(p, "\"event\":%u,", log->event);     /* 9 + 1 */
    p += sprintf(p, "\"flag\":%u,", log->flag);       /* 8 + 1 */
    p += sprintf(p, "\"state\":%u", log->state);      /* 7 + 1 */
    p += sprintf(p, "}");                             /* 1 */
    if (((intptr_t)p - (intptr_t)buf) > len)
        return 0;
    return ((intptr_t)p - (intptr_t)buf);
}
#endif
